import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.media.j3d.Canvas3D;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import nba2kmodtool.filedesc.BaseIffFile;
import nba2kmodtool.filedesc.IffDataFile;
import nba2kmodtool.filedesc.IffFactory;
import nba2kmodtool.filedesc.N2k3DModelPart;
import nba2kmodtool.filedesc.N2kModelRender;
import nba2kmodtool.filedesc.N2kPackageFile;
import nba2kmodtool.filedesc.N2kTextureFile;
import nba2kmodtool.util.PluginDDS;

public class MainBinFrameTest extends JFrame {

	private class DataTableSelListener implements ListSelectionListener {
		public void valueChanged(ListSelectionEvent evt) {
			int sel = dataTable.getSelectedRow();
			if (sel == -1) {
				return;
			}
			if (sel != selrow) {
				loader.clearScene();
				ishow.setIcon(null);
				subSel.removeAllItems();
				drawFrame.setVisible(false);
				selrow = sel;
				try {
					IffDataFile data = bin.getDataFiles()[sel];
					long type = data.getFileType();
					if (type == BaseIffFile.TYPE_TEXTURE) {
						N2kTextureFile texture = bin.readTextureFile(sel);
						showN2KTextureImage(texture);
					} else if (type == BaseIffFile.TYPE_PACKAGE) {
						pack = bin.readPackageFile(sel);
						int count = pack.getTextureNum();
						for (int i = 0; i < count; i++) {
							subSel.addItem("Texture: " + i);
						}
						int modelCount = pack.getModelNum();
						for (int i = 0; i < modelCount; i++) {
							subSel.addItem("Model: " + i);
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private static class OpenFileFilter extends FileFilter {

		private final String description;
		private final String descExt;

		OpenFileFilter(String description, String descExt) {
			this.description = description;
			this.descExt = descExt;
		}

		public boolean accept(File f) {
			if (f.isDirectory()) {
				return true;
			}
			String fileName = f.getName();
			int i = fileName.lastIndexOf('.');
			if ((i > 0) && (i < (fileName.length() - 1))) {
				String fileExt = fileName.substring(i + 1);
				if (descExt.equalsIgnoreCase(fileExt)) {
					curDir = f.getAbsolutePath();
					return true;
				}
			}
			return false;
		}

		public String getDescription() {
			return description;
		}
	}

	private static String curDir = "D:/n2k";

	private static final int VERSION = 2012;

	private static JFileChooser createFileChooser(String fileExt, String textFilesDesc) {
		JFileChooser fc = new JFileChooser();
		File dir = new File(curDir);
		if (!dir.exists()) {
			curDir = JFileChooser.class.getResource("/").getFile();
		}
		fc.setCurrentDirectory(new File(curDir));
		fc.setAcceptAllFileFilterUsed(false);
		fc.setFileFilter(new OpenFileFilter(textFilesDesc, fileExt));
		return fc;
	}

	public static BaseIffFile loadIff(File file) throws IOException {
		return IffFactory.readIffFile(file, VERSION);
	}

	public static void main(String[] args) {
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					//#2011
					File binfile = new File("F:/sotee/png005.iff");
					//binfile = new File("F:/sotee/png1608.iff");
					binfile = new File("F:/sotee/png1016.iff");
					//#2012					
					//binfile = new File("D:/fa/f066.iff");
					//binfile = new File("D:/fa/pg003.iff");					
					binfile = new File("D:/fa/png0143.iff");
					binfile = new File("D:/fa/png1153.iff");
					binfile = new File("D:/fa/png1538.iff");
					binfile = new File("D:/fa/team_125.iff");
					//binfile = new File("D:/fa/s000.iff");
					//binfile = new File("F:/2k12/ux000.iff");
					if (binfile == null) {
						JFileChooser chooser = createFileChooser("iff", "Nba2K X Iff");
						int option = chooser.showOpenDialog(null);
						if (JFileChooser.APPROVE_OPTION != option) {
							return;
						}
						binfile = chooser.getSelectedFile();
					}
					//File binfile = new File("D:/My Documents/s001.iff");
					//File binfile = new File("D:/My Documents/cloth_tri.iff");
					BaseIffFile iff = loadIff(binfile);
					if (iff.isCompressed()) {
						int sel = JOptionPane.showConfirmDialog(null, "IFF被压缩,要正常读取需先解压,是否现在解压?");
						if (sel == JOptionPane.OK_OPTION) {
							iff.writeDecompressFile();
							iff = loadIff(binfile);
						} else {
							return;
						}
					}
					MainBinFrameTest frame = new MainBinFrameTest(iff);
					frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
					System.exit(-1);
				}
			}
		});
	}

	private JPanel drawingPanel;

	private Canvas3D canvas;

	private JPanel showPane;

	private JTable dataTable;

	private JComboBox subSel;

	private N2k3DModelPart model;

	private N2kTextureFile mtext;

	private N2kModelRender loader;

	private BaseIffFile bin;

	private Image image;

	private BufferedImage texture;

	private JLabel ishow;

	private int selrow;

	private N2kPackageFile pack;

	private DrawFrame drawFrame;

	private static final String[] dataHeaders = { "文件序号", "文件类型", "文件块数" };

	public MainBinFrameTest(BaseIffFile binfile) throws IOException {
		this.setTitle("NBA2K12 IFF Frame Test");
		this.bin = binfile;
		// Initialize the GUI components
		initComponents();
		load();
	}

	public void export() {
		try {
			int index = dataTable.getSelectedRow();
			if (index < 0) {
				return;
			}
			System.out.println(index);
			File file = new File("D:/res.out");
			bin.writeIndexExportFile(file, index);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void exportModelFile(File file, N2k3DModelPart model) throws IOException {
		bin.exportModelFile(file, new N2k3DModelPart[] { model });
	}

	private void exportRes() throws IOException {
		int index = subSel.getSelectedIndex();
		if (index < 0) {
			index = dataTable.getSelectedRow();
			IffDataFile data = bin.getDataFiles()[index];
			long type = data.getFileType();
			if (type == BaseIffFile.TYPE_TEXTURE) {
				N2kTextureFile texture = bin.readTextureFile(index);
				String format = texture.getFileType();
				File file = new File("D:/res." + format.toLowerCase());
				bin.exportTextureFile(file, texture);
			}
			return;
		}
		int count = pack.getTextureNum();
		if (index < count) {
			N2kTextureFile texture = pack.getTextures()[index];
			String format = texture.getFileType();
			File file = new File("D:/res." + format.toLowerCase());
			bin.exportTextureFile(file, texture);
		} else {
			index = index - count;
			File file = new File("D:/res.n2km");
			N2k3DModelPart part = pack.getModels()[index];
			exportModelFile(file, part);
		}
	}

	private void importIffModel() throws IOException {
		int index = subSel.getSelectedIndex();
		if (index < 0) {
			return;
		}
		int count = pack.getTextureNum();
		if (index < count) {
			return;
		} else {
			N2k3DModelPart part = pack.getModels()[index];
			JFileChooser fileChooser = new JFileChooser();
			fileChooser.setCurrentDirectory(new File("D:/"));
			fileChooser.setAcceptAllFileFilterUsed(false);
			fileChooser.setFileFilter(new OpenFileFilter("Model Data File", "iff"));
			if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
				File file = fileChooser.getSelectedFile();
				BaseIffFile iff = loadIff(file);
				int fileNum = iff.getFileNum();
				StringBuffer impInfo = new StringBuffer();
				List<N2kPackageFile> packs = new ArrayList<N2kPackageFile>();
				int packIndex = 0;
				List<String> modelNames = new ArrayList<String>();
				for (int i = 0; i < fileNum; i++) {
					IffDataFile data = iff.getDataFiles()[i];
					long type = data.getFileType();
					if (type == BaseIffFile.TYPE_TEXTURE) {
					} else if (type == BaseIffFile.TYPE_PACKAGE) {
						N2kPackageFile packf = iff.readPackageFile(i);
						int modelCount = packf.getModelNum();
						if (modelCount > 0) {
							packs.add(packf);
							for (int j = 0; j < modelCount; j++) {
								N2k3DModelPart model = packf.getModels()[j];
								String modelIndex = String.format("%d-%d", packIndex, j);
								modelNames.add(modelIndex);
								impInfo.append(String.format("Model %s: vertex: %d, faceData: %d\n", modelIndex,
										model.getVertexNum(), model.getFaceDataSize()));
							}
							packIndex++;
						}
					}
				}
				if (impInfo.length() > 0) {
					impInfo.insert(
							0,
							String.format("source:\nvertex: %d, faceData: %d\nimport:\n", part.getVertexNum(),
									part.getFaceDataSize()));
					String sel = (String) JOptionPane.showInputDialog(null, impInfo.toString(),
							"Select witch Model to Import:", JOptionPane.QUESTION_MESSAGE, null, modelNames.toArray(),
							0);
					if (sel != null) {
						String[] indexes = sel.split("-");
						int pidx = Integer.parseInt(indexes[0]);
						int midx = Integer.parseInt(indexes[1]);
						N2kPackageFile pk = packs.get(pidx);
						if (bin.importIffModel(iff, pk, midx, part)) {
							JOptionPane.showMessageDialog(null, "Import IFF Model Complete!");
						}
					}
				}
			}
		}
	}

	private void importRes() throws IOException {
		int index = subSel.getSelectedIndex();
		JFileChooser fileChooser = new JFileChooser(new File("D:/"));
		fileChooser.setAcceptAllFileFilterUsed(false);
		if (index < 0) {
			index = dataTable.getSelectedRow();
			IffDataFile data = bin.getDataFiles()[index];
			long type = data.getFileType();
			if (type == BaseIffFile.TYPE_TEXTURE) {
				N2kTextureFile texture = bin.readTextureFile(index);
				String format = texture.getFileType();
				fileChooser.setFileFilter(new OpenFileFilter("Texture File", format));
				fileChooser.showOpenDialog(this);
				if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
					File file = fileChooser.getSelectedFile();
					bin.importTextureFile(file, texture);
				}
			}
			load();
			return;
		}
		int count = pack.getTextureNum();
		if (index < count) {
			N2kTextureFile texture = pack.getTextures()[index];
			String format = texture.getFileType();
			fileChooser.setFileFilter(new OpenFileFilter("Texture File", format));
			fileChooser.showOpenDialog(this);
			if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
				File file = fileChooser.getSelectedFile();
				bin.importTextureFile(file, texture);
			}
		} else {
			fileChooser.setFileFilter(new OpenFileFilter("Model Data File", "n2km"));
			if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
				File file = fileChooser.getSelectedFile();
				N2k3DModelPart[] models = pack.getModels();
				Object mode = JOptionPane.showInputDialog(null, "Select Import Mode:", "Import Mode",
						JOptionPane.INFORMATION_MESSAGE, null, new String[] { "All", "YXZ Only" }, "All");
				if (mode == null) {
					return;
				}
				int importMode = 0;
				if ("YXZ Only".equals(mode)) {
					importMode = 1;
				}
				bin.importModel(file, pack, importMode);
			}
		}
		load();
	}

	private void initComponents() {
		drawingPanel = new JPanel();
		JPanel tool = new JPanel();
		JButton button = new JButton("Load");
		button.setSize(200, 50);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					loadIff();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		tool.add(button, BorderLayout.NORTH);
		button = new JButton("LoadDDS");
		button.setSize(200, 50);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				loadDDS();
			}
		});
		tool.add(button, BorderLayout.NORTH);
		button = new JButton("ExportBin");
		button.setSize(200, 50);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				export();
			}
		});
		tool.add(button, BorderLayout.NORTH);
		button = new JButton("ExportRes");
		button.setSize(200, 50);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					exportRes();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		tool.add(button, BorderLayout.NORTH);
		button = new JButton("ImportRes");
		button.setSize(200, 50);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					importRes();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		tool.add(button, BorderLayout.NORTH);
		button = new JButton("ImportIffModel");
		button.setSize(200, 50);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					importIffModel();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		tool.add(button, BorderLayout.NORTH);
		button = new JButton("STOP");
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				loader.rotationModels(false);
			}
		});
		tool.add(button, BorderLayout.CENTER);
		add(tool, BorderLayout.NORTH);
		JPanel leftPanel = new JPanel();
		leftPanel.setPreferredSize(new Dimension(200, 600));
		JScrollPane listPanel = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		listPanel.setPreferredSize(new Dimension(200, 400));
		dataTable = new JTable(1, dataHeaders.length);
		dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		initDataTableHeader();
		dataTable.getSelectionModel().addListSelectionListener(new DataTableSelListener());
		listPanel.getViewport().add(dataTable);
		leftPanel.add(listPanel, BorderLayout.NORTH);

		subSel = new JComboBox();
		subSel.setPreferredSize(new Dimension(200, 50));
		subSel.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent evt) {
				subFileSelItemStateChanged(evt);
			}
		});
		JPanel subPanel = new JPanel();
		subPanel.add(subSel);
		leftPanel.add(subPanel, BorderLayout.SOUTH);
		drawingPanel.add(leftPanel);
		showPane = new JPanel();
		showPane.setLayout(new GridLayout(1, 2));
		showPane.setPreferredSize(new Dimension(600, 600));
		loader = new N2kModelRender();
		canvas = loader.createCanvas();
		canvas.setPreferredSize(new Dimension(600, 600));
		showPane.add(canvas);
		drawingPanel.add(showPane);
		ishow = new JLabel();
		showPane.add(ishow);
		drawingPanel.add(showPane);
		add(drawingPanel);
		this.drawFrame = new DrawFrame();
		drawFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
		pack();
	}

	private void initDataTableHeader() {
		TableColumnModel tableModel = dataTable.getColumnModel();
		TableColumn column;
		for (int i = 0; i < dataHeaders.length; i++) {
			String headerInfo = dataHeaders[i];
			column = tableModel.getColumn(i);
			column.setHeaderValue(headerInfo);
			column.setPreferredWidth(100);
		}
	}

	public void load() {
		try {
			TableColumnModel columnModel = dataTable.getColumnModel();
			dataTable.removeAll();
			DefaultTableModel model = (DefaultTableModel) dataTable.getModel();
			int fileCount = bin.getFileNum();
			model.setRowCount(fileCount);
			IffDataFile[] files = bin.getDataFiles();
			for (int i = 0; i < fileCount; i++) {
				int j = 0;
				IffDataFile res = files[i];
				setTableData(res.getFileSerial(), i, j++);
				setTableData(res.getFileType(), i, j++);
				dataTable.setValueAt(res.getPartNum(), i, j++);
			}
			File textfile = new File("D:/res.dds");
			PluginDDS dds = new PluginDDS();
			//texture = dds.readDDSFile(textfile);
			//loader.loadTexture(texture);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void loadDDS() {
		try {
			JFileChooser fileChooser = new JFileChooser(curDir);
			fileChooser.setAcceptAllFileFilterUsed(false);
			fileChooser.setFileFilter(new OpenFileFilter("Bitmap Texture File", "bmp"));
			fileChooser.setFileFilter(new OpenFileFilter("DDS Texture File", "dds"));
			if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
				File textfile = fileChooser.getSelectedFile();
				if (textfile.getName().endsWith(".bmp")) {
					texture = ImageIO.read(textfile);
				} else if (textfile.getName().endsWith(".dds")) {
					PluginDDS dds = new PluginDDS();
					texture = dds.readDDSFile(textfile);
				}
				image = texture;
				ishow.setIcon(new ImageIcon(image));
				loader.loadTexture(texture);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void loadIff() throws IOException {
		curDir = "F:/game/NBA 2K11/";
		JFileChooser fileChooser = new JFileChooser(curDir);
		fileChooser.setAcceptAllFileFilterUsed(false);
		fileChooser.setFileFilter(new OpenFileFilter("Nba2KX IFF File", "iff"));
		if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
			File file = fileChooser.getSelectedFile();
			this.bin = loadIff(file);
			if (bin.isCompressed()) {
				int sel = JOptionPane.showConfirmDialog(null, "IFF被压缩,要正常读取需先解压,是否现在解压?");
				if (sel == JOptionPane.OK_OPTION) {
					bin.writeDecompressFile();
					bin = loadIff(file);
				} else {
					return;
				}
			}
			load();
		}
	}

	private void setTableData(Number numb, int row, int column) {
		dataTable.setValueAt(Integer.toHexString(numb.intValue()).toUpperCase(), row, column);
	}

	private void showN2K3DModel(N2k3DModelPart model) throws IOException {
		loader.loadModelData(bin, model);
		drawFrame.loadModel(model);
		drawFrame.setVisible(true);
	}

	private void showN2K3DModels(N2k3DModelPart[] models) throws IOException {
		loader.loadModelDatas(bin, models);
	}

	private void showN2KTextureImage(N2kTextureFile texture) throws IOException {
		image = bin.readN2KTexture(texture);
		ishow.setIcon(new ImageIcon(image));
	}

	private void subFileSelItemStateChanged(java.awt.event.ItemEvent evt) {
		try {
			if (subSel.getSelectedIndex() == -1) {
				return;
			}
			int index = subSel.getSelectedIndex();
			int count = pack.getTextureNum();
			int modelCount = pack.getModelNum();
			if (subSel.getSelectedIndex() < count) {
				showN2KTextureImage(pack.getTextures()[index]);
			} else {
				index = index - count;
				N2k3DModelPart models[] = pack.getModels();
				N2k3DModelPart part = models[index];
				showN2K3DModel(part);
				//showN2K3DModels(models);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
